package controller;
import java.util.ArrayList;

import dao.BoardMementoDAO;
import entity.Board;
import entity.BoardMemento;
import entity.Movable;
import entity.Move;
import entity.Poem;
import entity.Word;
import gui.BoardApplication;

/**
 * This is the undo controller.
 */
public class UndoController{
	private Board board;
	private BoardApplication gui;

	/**
	 * Constructor of undo controller.
	 */
	public UndoController(BoardApplication gui, Board board){
		this.board = board;
		this.gui = gui;
	}

	/**
	 * Undo last move.
	 */
	public void undo(){
		Move m = board.undo();
		
		if(m != null){
			remove(m.getNewItems());
			add(m.getOldItems());
		}else{
			return;			
		}
		
		while(!m.isCheckpoint()){
			m = board.undo();
			
			if(m == null){
				break;
			}

			remove(m.getNewItems());
			add(m.getOldItems());
		}

		gui.canvas.repaint();
		
		BoardMemento bm = new BoardMemento(board);
		BoardMementoDAO dao = new BoardMementoDAO();
		dao.saveBoardMemento(bm, gui.getRunMode(), BoardMementoDAO.FILE_NAME);
	}

	/**
	 * Redo last undo.
	 */
	public void redo(){
		Move m = board.redo();
		boolean first = true;
		
		while(m != null && (first || !m.isCheckpoint())){
			first = false;
			
			remove(m.getOldItems());
			add(m.getNewItems());
			
			m = board.redo();
		}
		
		if(m != null){
			board.undo();
			System.out.println("MORE");
		}

		gui.canvas.repaint();
		
		BoardMemento bm = new BoardMemento(board);
		BoardMementoDAO dao = new BoardMementoDAO();
		dao.saveBoardMemento(bm, gui.getRunMode(), BoardMementoDAO.FILE_NAME);
	}
	
	/**
	 * Remove words or poems form Board.
	 * */
	public void remove(ArrayList<Movable> list){
		for(Movable item : list){
			if(item instanceof Word){
				board.removeWord((Word) item);
			}else if(item instanceof Poem){
				board.getPoems().remove((Poem) item);
				
				for(Word w : ((Poem) item).getWords()){
					board.removeWord(w);
				}
			}
		}
	}
	
	/**
	 * Add words or poems to the Board.
	 */
	public void add(ArrayList<Movable> list){
		for(Movable item : list){
			if(item instanceof Word){
				board.addWord((Word) item);
			}else if(item instanceof Poem){
				for(Word w : ((Poem) item).getWords()){
					if(board.getProtectedWords().contains(w)
					|| board.getUnprotectedWords().contains(w)){
						board.removeWord(w);
					}
					
					board.addWord(w);
				}
				
				if(board.getPoems().contains((Poem) item)){
					board.getPoems().remove((Poem) item);
				}
				
				board.getPoems().add((Poem) item);
				((Poem) item).setPosition(item.getX(), item.getY());
			}
		}
	}
	
	/**
	 * Return board.
	 */
	public Board getBoard() {
		return board;
	}

	/**
	 * Return gui.
	 */
	public BoardApplication getGui() {
		return gui;
	}
}
